package com.boilermaker.springbootdemo;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;

/*
        接收参数的练习：
        请求中的参数包括：
            URL中查询字符串里的参数
            正文body 中的参数
            URL中的资源定位部分也可能带有参数
        前两类参数称为请求参数，最后一类参数称为路径参数，路径参数比较少见。
        其中，正文中可以传递 JSON 格式的数据
*/

@RequestMapping("/Request")
@RestController
public class RequestController {
    // 接收请求参数（查询字符串中的参数和 body 中的参数）
    // RequestParam 用于重命名。一旦使用该注解则默认该参数为必传参数，如果客户端没有传此参数会报 400
    // 从 HTTP 协议传过来的参数均是字符串，Spring 会根据后端定义的参数类型进行转换，若无法转换也会报 400
    @RequestMapping("/r1")
    public String r1(@RequestParam("keyword") String key) {
        return "响应为" + key;
    }

    // 可以设置为非必传参数，此时不传参数会默认为 null
    @RequestMapping("/r2")
    public String r2(@RequestParam(value = "q", required = false) String keyword) {
        return "响应为" + keyword;
    }

    @RequestMapping("/r3")
    public int[] r3(int[] arr) {
        return arr;
    }

    @RequestMapping("/r4")
    // 此时 RequestParam 表示将传入的数组绑定为一个 List，如果不加该注解将无法构造 List
    public String r4(@RequestParam List<Integer> list) {
        return list.toString();
    }

    @RequestMapping("/r5")
    // 接收 JSON 格式的数据
    // 使用 JSON 传递数据的情况占绝大多数
    // Spring 已经帮我们集成了 Jackson 工具，使用 RequestBody 注解就可以从前端接收到 JSON 数据并赋值给 Java 对象
    public String r5(@RequestBody UserInfo userInfo) {
        System.out.println("接收到：" + userInfo);
        return "接收到：" + userInfo;
    }

    // 从 URL 中取值，也就是取路径参数，{} 中的数据即要取的值
    @RequestMapping("/r6/{r7}")
    // PathVariable 即路径中的变量，该注解用于从 URL 中取值
    public String r6(@PathVariable String r7) {
        return "从 URL 中获取的r7为" + r7;
    }

    @RequestMapping("/r8/{r9}/{r10}")
    public String r8(@PathVariable String r10, @PathVariable("r9") String name) {
        return r10 + name;
    }

    // 接收前端传来的文件
    @RequestMapping("/r11")
    public String r11(@RequestPart MultipartFile file) throws IOException {
        // 得到文件名
        String filename = file.getOriginalFilename();
        // transferTo 内部封装了 InputStream 和 OutputStream
        // File 需要指定到具体文件而不能是路径
        file.transferTo(new File("D:\\", "UserFile.jpg"));
        return "已接收：" + filename;
    }

    // 使用 HttpServletRequest 获取 Cookie
    // HTTP 请求 Header 中的全部数据都会被封装在 HttpServletRequest 容器中
    @RequestMapping("/r12")
    public String r12(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        StringBuilder builder = new StringBuilder();
        if (cookies == null) return "无 Cookie 设置！";
        for (Cookie c : cookies) builder.append(c.getName()).append(":").append(c.getValue()).append(",");
        return "Cookie 信息为：" + builder;
    }

    // 上面是在使用 Servlet 原生的 API 获取 Cookie，实际上 Spring 也为我们封装了获取 Cookie 的注解
    // 这种方法不常用，因为一次只能获取一个值
    @RequestMapping("/r13")
    public String r13(@CookieValue("name") String name) {
        return name;
    }

    //设置和获取 Session：
    @RequestMapping("/set")
    public String set(HttpServletRequest request, String userid, String password) {
        /* getSession()方法会提取请求中SessionId这个Cookie，并根据SessionId获取对应的Session对象
         如果检索到该Cookie，则表示服务器已经在内存中保存了该session，该方法会返回现有的Session
         如果不存在，则会生成SessionId，创建新的Session，在响应中返回该SessionId给客户端
         因此getSession()默认返回非空session，若需避免创建新Session，应使用getSession(false)。
         */
        HttpSession session = request.getSession();
        String id = (String) session.getAttribute("ID");
        // 向其中添加用户名和密码
        if (!StringUtils.hasLength(id)) {
            session.setAttribute("ID", userid);
            session.setAttribute("password", password);
        }
        return "设置 Session 成功！";
    }

    // session 保存在服务器内存中，重启服务器即会清除
    @RequestMapping("/get")
    public String get(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String id = (String) session.getAttribute("ID");
        if (!StringUtils.hasLength(id)) return "登录失效";
        else return "登陆成功，用户名为" + id;
    }

    // 获取 Session 的第二种方式，即直接调用Session对象，不存在时会自动创建
    @RequestMapping("/r14")
    public String get2(HttpSession session) {
        String id = (String) session.getAttribute("ID");
        if (!StringUtils.hasLength(id)) return "登录失效";
        else return "登陆成功，用户名为" + id;
    }

    // 获取 Session 的第三种方式，使用注解
    @RequestMapping("/r15")
    public String get3(@SessionAttribute("ID") String id) {
        if (!StringUtils.hasLength(id)) return "登录失效";
        else return "登陆成功，用户名为" + id;
    }

    // 获取Header中的内容
    @RequestMapping("/r16")
    public String getUserAgent(HttpServletRequest request) {
        return request.getHeader("User-Agent");
    }

    // 使用注解获取Header中的内容
    @RequestMapping("/r17")
    public String getUserAgent2(@RequestHeader("User-Agent") String ua) {
        return ua;
    }
}
